package BookStore.managers_impl.AuctionMgr;

import java.io.BufferedReader;
import java.nio.charset.Charset;
import java.util.ArrayList;

import org.apache.log4j.Logger;
import org.omg.CORBA.ORB;

import be.fundp.info.util.logging.MyLogger;

import BookStore.BookStoreMain;
import BookStore.common.Book;
import BookStore.managers.AuctionMgr_Iface.AuctionMgrPOA;
import Util.CSVBookParser;
import Util.Util;

/**
 * Manager aiming to manage the auction started by the online library
 * 
 */
public class AuctionMgr extends AuctionMgrPOA {
	private ORB orb;
	private String myID;
	private final static Logger logger = MyLogger.getLogger(Class.class);

	public AuctionMgr(ORB orb, String id) {
		this.orb = orb;
		myID = id;
	}

	@Override
	public float getBookPrice(String isbn, float price) {

		logger.info(isbn + ":" + price);
		// retrieve the purchase price for the book 'isbn'
		Float purchase = getPurchasePrice(isbn);
		if (purchase == null)// book store does not have this book
			return -1;

		purchase = RoundUp(purchase);
		// retrieve the minimum margin
		String m = Util.getPropertiesAttribute(BookStoreMain.prop, "margin");
		if (m == null) {
			logger.info("[ERROR]:" + BookStoreMain.prop + " is absent.");
			return -1;
		}

		Float margin = Float.parseFloat(m);
		if (margin == null)// margin error
			return -1;

		// calculate the minimum price the book store can propose for this book
		float min = ((float) ((int) (margin * purchase)) / 100) + purchase;
		min = RoundUp(min);


		if (price < min)
			return -1;

		float diff = price - min;
		int n = (int) (diff * 100);

		// calculate a random price to propose
		double random = Math.random();
		random = random * n;
		n = (int) random;
		diff = (float) n / 100;

		float myprice = price - diff;
		myprice = RoundUp(myprice);
		logger.info("my new price:" + myprice);

		return myprice;
	}

	/**
	 * Round up a number by keeping two numbers after the comma
	 * 
	 * @param f
	 *            number to round up
	 * @return the number by keeping only two numbers after comma
	 */
	private static float RoundUp(float f) {
		java.text.DecimalFormat df = new java.text.DecimalFormat("0.##");
		String res = df.format(f);
		res = res.replaceAll(",", ".");
		return Float.parseFloat(res);
	}

	/**
	 * Get the purchase price of a book
	 * 
	 * @param isbn
	 *            book isbn
	 * @return the purchase price
	 */
	private Float getPurchasePrice(String isbn) {
		CSVBookParser parser = new CSVBookParser();
		BufferedReader r = parser.open(BookStoreMain.getCSV(),
				Charset.forName("UTF-8"));
		boolean found = false;
		Book b = null;
		// we find the book in the bookstore CSV
		while (!found) {
			b = parser.parseLine(r);
			if (b == null)
				break;
			if (b.isbn.equals(isbn))
				found = true;
		}

		if (b == null)// provider does not have this book
			return null;
		return b.purchase_price;

	}

	@Override
	public boolean buyBook(String ISBN, float price, int sellNumber) {
		String save = Util.getPropertiesAttribute(BookStoreMain.prop, "save");

		// we register the book buying in the CSV file
		boolean b = CSVBookParser.writeFile(ISBN + ";" + price, save);
		if (b)
			logger.info("sell completed : isbn =" + ISBN + " price =" + price);
		else
			logger.info("sell not recorded... file problem");
		return true;
	}

	@Override
	public void initLaunch(String isbn, float price, String[] IORList,
			int sellNumber) {
		ArrayList<String> list = new ArrayList<String>();
		int[] indexList = new int[IORList.length + 1];
		for (int i = 0; i < indexList.length; i++)
			indexList[i] = i;

		for (int i = 0; i < IORList.length; i++)
			list.add(IORList[i]);
		list.add("");

		launchAuction(isbn, price, list, sellNumber);

	}

	private void launchAuction(String isbn, float price,
			ArrayList<String> IORList, int sellNumber) {
		logger.info("new auction launched by BS " + myID + " :" + isbn
				+ " price=" + price);

		float minPrice = price;

		for (int i = 0; i < IORList.size(); i++) {

			if (IORList.get(i).equals("")) {
				// me
				float pr = this.getBookPrice(isbn, price);
				if (pr != -1) {
					// I propose a lower or equal price
					logger.info("BS " + myID + " proposes a new price:" + pr);
					if (pr < minPrice)
						minPrice = pr;
				} else {
					// I cannot propose a better price
					logger.info("BS " + myID + " does not propose a new price:"
							+ pr);
					IORList.remove(i);
					i--;
				}

			} else {
				// other BS
				try {
					BookStore.managers.AuctionMgr_Iface.AuctionMgr mgr = (BookStore.managers.AuctionMgr_Iface.AuctionMgr) orb
							.string_to_object(IORList.get(i));
					float pr = mgr.getBookPrice(isbn, price);
					if (pr != -1) {
						// BS proposes a price
						logger.info("BS proposes a new price:" + pr);
						if (pr < minPrice)
							minPrice = pr;
					} else {
						// BS cannot propose a lower price
						IORList.remove(i);
						i--;
					}
				} catch (Exception e) {
					// BS is not connected
					IORList.remove(i);
					i--;
				}
			}

		}

		if (IORList.size() == 1) {// only one BS
			// auction over
			logger.info("It remains only one bookstore");
			if(IORList.get(0).equals("")){
				//me
				buyBook(isbn, price, sellNumber);
			}else{
				BookStore.managers.AuctionMgr_Iface.AuctionMgr mgr = (BookStore.managers.AuctionMgr_Iface.AuctionMgr) orb.string_to_object(IORList.get(0));
				mgr.buyBook(isbn, price, sellNumber);
			}
			logger.info("final sell price = " + price);
			
		} else {

			if (minPrice == price) {
				// auction is over but several BS are candidates

				// we randomly choose a book store
				double random = Math.random();
				random = random * IORList.size();
				int r = (int) random;
				logger.info("random chosen book store");
				if(IORList.get(r).equals(""))
					//me
					buyBook(isbn, minPrice, sellNumber);
				else
					((BookStore.managers.AuctionMgr_Iface.AuctionMgr)orb.string_to_object(IORList.get(r))).buyBook(isbn, minPrice, sellNumber);
				
				logger.info("final sell price = " + minPrice);
			} else {
				// auction continues
				launchAuction(isbn, minPrice, IORList, sellNumber);
			}
		}

	}

}
